package io.github.mymonstercat.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.benjaminwan.ocrlibrary.TextBlock;
import com.google.gson.stream.JsonReader;
import io.github.mymonstercat.entity.HwResult;
import io.github.mymonstercat.entity.OCRStandardRes;
import io.github.mymonstercat.entity.attachmentCheck.AttachmentConfig;
import io.github.mymonstercat.entity.attachmentCheck.AttachmentResponse;
import io.github.mymonstercat.entity.attachmentCheck.AttachmentType;
import io.github.mymonstercat.service.AttachmentCheckService;
import io.github.mymonstercat.service.TicketVisitsService;
import io.github.mymonstercat.tools.model.AiResponse;
import io.github.mymonstercat.utils.GetJsonData;
import io.github.mymonstercat.utils.TextInfoTransformer;
import io.github.mymonstercat.utils.baidu.BaiduNLPUtils;
import io.github.mymonstercat.utils.baidu.BaiduOCRUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class AttachmentCheckServiceImpl implements AttachmentCheckService {

    @Resource
    private GetJsonData getJsonData;

    @Autowired
    private TicketVisitsService ticketVisitsService;

    @Override
    public AttachmentResponse attachmentCheck(String attachmentCode, String pdfPath, String imageOutputPath, AttachmentType attachmentType, String fileId, Integer fileType) throws Exception {

        // 加载持久化的 JSON 配置文件
        List<AttachmentConfig> attachmentConfigData = this.getJson();

        // 根据附件编码获取匹配的 AttachmentConfig
        AttachmentConfig matchingConfig = attachmentConfigData.stream()
                .filter(config -> attachmentCode.equals(config.getAttachmentCode()))
                .findFirst()
                .orElse(null);

        if (matchingConfig == null) {
            return AttachmentResponse.error("配置文件中找不到对应编码");
        }

        List<String> headerValues = matchingConfig.getHeaderValues();
        List<String> bodyValues = matchingConfig.getBodyValues();

        // 创建输出文件夹（如果不存在）
        File folder = new File(imageOutputPath);
        if (!folder.exists()) {
            folder.mkdirs();
        }

        // 存储识别到的 words
        StringBuilder combinedWords = new StringBuilder();

        AttachmentResponse response = null;

        if (fileType == 2){
            response = handlePDF(pdfPath, imageOutputPath, attachmentType, attachmentCode, headerValues, bodyValues, combinedWords);
        } else if (fileType == 1) {
            response = handleIMAGE(pdfPath,attachmentType,attachmentCode, headerValues,bodyValues, combinedWords);
        }else {
            return AttachmentResponse.error("文件类型有误");
        }

        if (response != null) {
            return response;
        }

        log.info("未找到匹配，开始整理提示词");
        // 输出组合的 words 字符串
        String resultWords = combinedWords.length() > 0 ? combinedWords.substring(0, combinedWords.length() - 1) : "";
        String filteredText = filterText(resultWords);

        // 调用当前附件编码的提示词
        String promptWords = handleNoMatch(attachmentCode, filteredText);
        // 请求华为NLP大模型
        log.info("开始调用大模型接口");

        String responseStr = "";
//        try {
//            responseStr = HwNLPUtils.requestNLPText(promptWords);
//        }catch (Exception e){
//            return AttachmentResponse.error("请求NLP接口失败");
//        }

        try{
            AiResponse aiResponse = BaiduNLPUtils.startAigcNew2(promptWords);
            List<String> data = aiResponse.getData();
            responseStr = data.get(0);
        }catch (Exception e){
            return AttachmentResponse.error("请求NLP接口失败");
        }

        System.out.println(responseStr);
        String check = null;
        String explain = null;
        try {
            String[] results = extractCheckAndExplain(responseStr);
            check = results[0];
            explain = results[1];
            // 继续处理 check 和 explain
        } catch (IllegalArgumentException e) {
            // 处理异常，例如记录日志或返回错误响应
            log.error(e.getMessage());
            return AttachmentResponse.success("false", "false","大模型返回结果格式有误");
        }

        String message;

        if (check.equals("true")) {
            message = "大模型校验成功，理由：" + explain;
        } else if (check.equals("false")) {
            message = "大模型校验失败，理由：" + explain;
        } else {
            return AttachmentResponse.success("false", "false","大模型的返回结果格式有误，check不是true/false");
        }

        ticketVisitsService.saveVisits(message, "log", fileId);
        return AttachmentResponse.success(check, "false", "大模型校验");
    }

    private String handleNoMatch(String attachmentCode, String combinedWords){
        // TODO 路径写死了，需要写成配置的形式
        String jsonString = readJsonFile("data/AttachmentPromptTemplate.json");
        String attachContentStart = "###附件文本开始###";
        String attachContentEnd = "###附件文本结束###";
        String promptWord = getPromptWord(jsonString, attachmentCode);
        String taskPromptTemplate = getPromptWord(jsonString, "taskPromptTemplate");
        String promptWords = taskPromptTemplate + attachContentStart + combinedWords + attachContentEnd + promptWord;
        return promptWords;
    }

    /**
     * 获取json格式的特征数据
     *
     * @return List<OcrTempateConfigs>
     */
    private List<AttachmentConfig> getJson() {
        return getJsonData.getTestData("AttachmentConfigs.json", AttachmentConfig.class);
    }

    /**
     * 过滤华为OCR识别文本中的特殊字符
     *
     *
     */
    public String filterText(String input) {
        // 使用正则表达式只保留汉字和逗号
        if (input == null) {
            return null; // 处理 null 情况
        }
        // 使用正则表达式去除不需要的特殊字符，保留字母、数字、汉字、/、,、(、)
        return input.replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5(),]", ""); // 只保留指定的字符
    }


    private static String readJsonFile(String filePath) {
        try (InputStream inputStream = JsonReader.class.getClassLoader().getResourceAsStream(filePath);
             BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {

            if (bufferedInputStream == null) {
                throw new RuntimeException("找不到文件: " + filePath);
            }

            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, bytesRead);
            }
            return byteArrayOutputStream.toString(StandardCharsets.UTF_8.name());
        } catch (Exception e) {
            throw new RuntimeException("读取文件时出错", e);
        }
    }

    private static String getPromptWord(String jsonString, String attachmentCode) {
        JSONObject jsonObject = JSON.parseObject(jsonString);
        String proStr = jsonObject.getString(attachmentCode); // 直接根据附件编码获取提示词
        if (proStr == null){
            return "";
        }
        return proStr;
    }

    private static Boolean noStandardBodyMatch(List<String> bodyValues, OCRStandardRes ocrStandardRes) {
        boolean matchFound = true; // 假设所有值都匹配
        for (String bodyValue : bodyValues) {
            boolean foundMatch = false; // 记录当前 bodyValue 是否找到匹配
            for (OCRStandardRes.wordsBlock wordsBlock : ocrStandardRes.getWordsBlockList()) {
                if (wordsBlock.getWords().contains(bodyValue)) {
                    foundMatch = true; // 找到匹配
                    break; // 退出内层循环
                }
            }
            if (!foundMatch) { // 如果没有找到匹配
                matchFound = false; // 设置 matchFound 为 false
                break; // 退出外层循环
            }
        }
        return matchFound;
    }

    public static String[] extractCheckAndExplain(String content) {
//        JSONObject jsonResponse = JSON.parseObject(responseStr);
//        JSONArray choices = jsonResponse.getJSONArray("choices");
//
//        if (choices == null || choices.isEmpty()) {
//            throw new IllegalArgumentException("No choices available in the response.");
//        }
//
//        JSONObject messageObject = choices.getJSONObject(0).getJSONObject("message");
//        if (messageObject == null) {
//            throw new IllegalArgumentException("Message object is missing.");
//        }
//
//        String content = messageObject.getString("content");
        if (content == null || !content.contains("```json")) {
            throw new IllegalArgumentException("Content is missing or does not contain JSON part.");
        }

        // Extract the JSON part
        String jsonPart = content.split("```json")[1].split("```")[0].trim();
        JSONObject extractedJson = JSON.parseObject(jsonPart);

        // 获取 check 和 explain 值为字符串
        String check = extractedJson != null ? extractedJson.getString("check") : null;
        String explain = extractedJson != null ? extractedJson.getString("explain") : null;

        // 检查 check 和 explain 是否为 null
        if (check == null || explain == null) {
            throw new IllegalArgumentException("Check or explain value is missing.");
        }

        return new String[]{check, explain};
    }

    public AttachmentResponse handlePDF(String pdfPath, String imageOutputPath,
                                               AttachmentType attachmentType,
                                               String attachmentCode, List<String> headerValues,
                                               List<String> bodyValues, StringBuilder combinedWords) throws Exception {
        // 加载 PDF 文件
        File pdfFile = new File(pdfPath);
        PDDocument document = PDDocument.load(pdfFile);
        PDFRenderer pdfRenderer = new PDFRenderer(document);

        int maxPages = Math.min(10, document.getNumberOfPages());
        for (int page = 0; page < maxPages; page++) {
            // 将 PDF 页转换为图片
            BufferedImage image = pdfRenderer.renderImageWithDPI(page, 250, ImageType.RGB);
            String tempImagePath = imageOutputPath + "page_" + page + ".png";
            ImageIO.write(image, "jpg", new File(tempImagePath));

            // 处理 OCR 结果
            AttachmentResponse response = processOCR(tempImagePath, attachmentType, attachmentCode, headerValues, bodyValues, combinedWords);
            if (response != null) {
                document.close();
                return response;
            }

            // 删除临时图片文件
            new File(tempImagePath).delete();
        }
        document.close();
        return null;
    }

    public AttachmentResponse handleIMAGE(String imagePath,
                                                 AttachmentType attachmentType,
                                                 String attachmentCode, List<String> headerValues,
                                                 List<String> bodyValues, StringBuilder combinedWords) throws Exception {
        return processOCR(imagePath, attachmentType, attachmentCode, headerValues, bodyValues, combinedWords);
    }

    private AttachmentResponse processOCR(String filePath,
                                                 AttachmentType attachmentType,
                                                 String attachmentCode, List<String> headerValues,
                                                 List<String> bodyValues, StringBuilder combinedWords) throws Exception {
        // 使用华为 OCR 识别文本
//        String resstr = "";
//        try {
//            resstr = HwOCRUtils.recognizeGeneralText(filePath);
//        }catch (Exception e){
//            return AttachmentResponse.error("华为OCR识别异常");
//        }
//
//        HwResult hwResult = JSONObject.parseObject(resstr, HwResult.class);
//
//        hwResult.cleanWords();


        // 使用百度 OCR 识别文本
        ArrayList<TextBlock> baiduResult = BaiduOCRUtils.recognizeGeneralText(filePath);

        // 将百度 OCR 结果转换为 OCRStandardRes
        TextInfoTransformer textInfoTransformer = new TextInfoTransformer();
        OCRStandardRes ocrStandardRes = textInfoTransformer.baiduOCRTransform(baiduResult);

        // 组合识别到的 words
        for (OCRStandardRes.wordsBlock block : ocrStandardRes.getWordsBlockList()) {
            combinedWords.append(block.getWords()).append(",");
        }

        // 根据附件类型检查 OCR 结果
        if (attachmentType == AttachmentType.STANDARD) {
            return checkStandardAttachment(ocrStandardRes, attachmentCode, headerValues);
        } else {
            return checkNonStandardAttachment(ocrStandardRes, bodyValues);
        }
    }

    private AttachmentResponse checkStandardAttachment(OCRStandardRes ocrStandardRes,
                                                              String attachmentCode, List<String> headerValues) {
        for (OCRStandardRes.wordsBlock block : ocrStandardRes.getWordsBlockList()) {
            String words = block.getWords();

            // 检查是否存在 "附件编码: xxxx"
            if (words.contains(attachmentCode)) {
                return AttachmentResponse.success("true", "true", "附件编码校验成功");
            }

            // 检查是否存在任何表头值
            for (String header : headerValues) {
                if (words.contains(header)) {
                    return AttachmentResponse.success("true", "true", "表头校验成功");
                }
            }
        }
        return null;
    }

    private AttachmentResponse checkNonStandardAttachment(OCRStandardRes ocrStandardRes,
                                                                 List<String> bodyValues) {
        boolean matchFound = false;
        for (OCRStandardRes.wordsBlock block : ocrStandardRes.getWordsBlockList()) {
            String words = block.getWords();

            if (bodyValues.get(0).equals("*")) {
                // 如果第一个元素是 "*"
                matchFound = bodyValues.stream().skip(1).anyMatch(words::contains);
            } else {
                // 如果第一个元素不是 "*"
                matchFound = noStandardBodyMatch(bodyValues, ocrStandardRes);
            }

            if (matchFound) {
                return AttachmentResponse.success("true", "true", "非标准附件表内校验成功");
            }
        }
        return null;
    }

    public static void main(String[] args) {
        String content = "{\"id\": \"\", \"created\": 1727164064654, \"choices\": [{\"index\": 0, \"message\": {\"content\": \"以下是对给定文本中附件信息的分析和提取结果，整理成 JSON格式:\\n\\n```json\\n{\\n  \\\"check\\\": true,\\n  \\\"explain\\\": \\\"文本中包含'工程合同类结算确认单',并且有提及到'审定金额'和'结算金额',因此 check字段为 true,说明文本中包含了附件相关的信息。\\\"\\n}\\n```\\n\\n分析说明:\\n1.文本中明确提到了'工程合同类结算确认单',这与附件类型匹配。\\n2.文本中也提到了具体的'审定金额'和'结算金额',这可以确认附件中包含了这些关键信息。\\n3.因此，根据给定的字段和说明，文本中确实包含了工程合同类结算确认单及其相关的关键信息，所以 check字段为`true`。\\n4. explain字段中提供了为何 check字段为 true的详细解释，即文本中包含了附件的具体内容和关键数据。\"}}], \"usage\": {}}";
        String[] strings = extractCheckAndExplain(content);
        String a = strings[0];
        String b = strings[1];
        System.out.println(a);
        System.out.println(b);
    }
}
